﻿#include <occmesh/api/halfmesh.h>

HalfMesh::HalfMesh(const std::vector<TopoDS_Shape> &shapes) : m_shapes(shapes)
{
}

HalfMesh::~HalfMesh()
{
    for (auto e : m_halfEdges)
        delete e;
    for (auto w : m_wires)
        delete w;
    for (auto v : m_vertices)
        delete v;
    for (auto e : m_edges)
        delete e;
}

void HalfMesh::BuildTopo()
{
    BuildWire();
    BuildEdges();
    BuildVertices();

    for (auto wire : m_wires)
        wire->RebuildWire();

    BuildNormals();
    BuildPerpTangents();
}

void HalfMesh::BuildGeom()
{
}

void HalfMesh::BuildCoons()
{
    for (auto wire : m_wires)
        if (wire->Face().IsNull())
            wire->SetFace(std::make_shared<Coons>()->Covering(wire));
}

void HalfMesh::BuildFilling()
{
}

std::vector<TopoDS_Face> HalfMesh::BuildResults() const
{
    std::vector<TopoDS_Face> faces;
    for (auto wire : m_wires)
        faces.push_back(wire->Face());
    return faces;
}

void HalfMesh::BuildWire()
{
    // 构建 wire 拓扑
    TopExp_Explorer Ex;
    for (auto shape : m_shapes)
    {
        std::vector<TopoDS_Edge> edges;
        for (Ex.Init(shape, TopAbs_EDGE); Ex.More(); Ex.Next())
            edges.push_back(TopoDS::Edge(Ex.Current()));

        // 修复连接关系
        edges = OCCUtils::GetEdgesInOrder(edges, HalfParamData::fittingEdgeSample);

        // 构建连接关系
        HalfEdge *first = nullptr, *e1 = nullptr, *e2 = nullptr;
        for (auto edge : edges)
        {
            e2 = new HalfEdge(edge);
            m_halfEdges.push_back(e2);

            if (first == nullptr)
                first = e2;
            else
            {
                e1->next = e2;
                e2->prev = e1;
            }
            e1 = e2;
        }
        first->prev = e1;
        e1->next = first;

        m_wires.push_back(new Wire(first));
    }
}

void HalfMesh::BuildEdges()
{
    for (int i = 0; i < m_halfEdges.size(); i++)
    {
        if (m_halfEdges[i]->edge == nullptr)
            m_edges.push_back(new Edge(m_halfEdges[i]));

        for (int j = i + 1; j < m_halfEdges.size(); j++)
        {
            if (m_halfEdges[i]->Overlap(m_halfEdges[j]))
            {
                std::cout << i << " and " << j << "  Overlap!" << std::endl;
                m_halfEdges[i]->twin = m_halfEdges[j];
                m_halfEdges[j]->twin = m_halfEdges[i];
                m_halfEdges[j]->edge = m_halfEdges[i]->edge;
            }
        }
    }
}

void HalfMesh::BuildVertices()
{
    // 建立每条边的顶点
    for (int i = 0; i < m_edges.size(); i++)
    {
        // 在这里创建顶点，是为了避免重复创建
        if (m_edges[i]->startVertex == nullptr)
        {
            m_edges[i]->startVertex = new Vertex(m_edges[i]);
            m_vertices.push_back(m_edges[i]->startVertex);
        }

        if (m_edges[i]->endVertex == nullptr)
        {
            m_edges[i]->endVertex = new Vertex(m_edges[i]);
            m_vertices.push_back(m_edges[i]->endVertex);
        }

        // 连接其它重合顶点的边
        for (int j = i + 1; j < m_edges.size(); j++)
            m_edges[i]->ConnectEdge(m_edges[j]);
    }

    // 现在每个顶点只有一个边的信息，要补全顶点和边的连接关系
    for (auto v : m_vertices)
        v->FindEdges();

    // 为了捏合顶点，先累计顶点
    for (int i = 0; i < m_halfEdges.size(); i++)
        m_halfEdges[i]->AccumulateVertex();
}

void HalfMesh::BuildNormals()
{
    // 计算法向
    for (auto wire : m_wires)
    {
        auto half = wire->halfEdge;
        do
        {
            half->AccumulateNormal();
            half = half->next;
        } while (half != wire->halfEdge);
    }
}

void HalfMesh::BuildPerpTangents()
{
    for (auto wire : m_wires)
    {
        auto half = wire->halfEdge;
        do
        {
            half->BuildPerpTangent();
            half = half->next;
        } while (half != wire->halfEdge);
    }
}
